package org.origin.centre.security.user;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.origin.centre.model.consts.XConst;
import org.origin.centre.support.utils.MapUtil;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.*;

/**
 * 系统用户Entity
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
@JsonIgnoreProperties(value = {"password"})
public class XUser extends HashMap<String, Object> implements UserDetails, Serializable {
    private static final long serialVersionUID = 1L;

    @Override
    public String getUsername() {
        return MapUtil.getString(this, XConst.ACCOUNT);
    }

    @JsonIgnore
    @Override
    public String getPassword() {
        return MapUtil.getString(this, XConst.PASSWORD);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<?> collection = MapUtil.getCollection(this, XConst.AUTHORITIES);
        if (collection != null && collection.size() > 0) {
            List<GrantedAuthority> authorities = new ArrayList<>();
            for (Object item : collection) {
                if (item instanceof GrantedAuthority) {
                    authorities.add((GrantedAuthority) item);
                } else if (item instanceof String) {
                    authorities.add(new SimpleGrantedAuthority((String) item));
                }
            }
            return authorities;
        }
        return new ArrayList<SimpleGrantedAuthority>();
    }

    @Override
    public boolean isAccountNonLocked() {
        return this.matches(this.getStatus(), "1|2|3|4");
    }

    @Override
    public boolean isEnabled() {
        return this.matches(this.getStatus(), "1|3|4");
    }

    @Override
    public boolean isAccountNonExpired() {
        return this.matches(this.getStatus(), "1|2|4");
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return this.matches(this.getStatus(), "1|2|3");
    }

    public String getId() {
        return MapUtil.getString(this, XConst.ID);
    }

    public String getStatus() {
        return MapUtil.getString(this, XConst.STATUS);
    }

    public String getAccount() {
        return MapUtil.getString(this, XConst.ACCOUNT);
    }

    public boolean isAdmin() {
        return MapUtil.getBool(this, XConst.ADMIN);
    }

    public String getOrgId() {
        return MapUtil.getString(this, XConst.ORG_ID);
    }

    public String getClientId() {
        return MapUtil.getString(this, XConst.CLIENT_ID);
    }

    public String getDataScope() {
        return MapUtil.getString(this, XConst.DATA_SCOPE);
    }

    public XUser setId(String id) {
        this.put(XConst.ID, id);
        return this;
    }

    public XUser setAccount(String username) {
        this.put(XConst.ACCOUNT, username);
        return this;
    }

    public XUser setPassword(String password) {
        this.put(XConst.PASSWORD, password);
        return this;
    }

    public XUser setStatus(Integer status) {
        this.put(XConst.STATUS, status);
        return this;
    }

    public XUser setAdmin(boolean isAdmin) {
        this.put(XConst.ADMIN, isAdmin);
        return this;
    }

    public XUser setOrgId(String orgId) {
        this.put(XConst.ORG_ID, orgId);
        return this;
    }

    public XUser setClientId(String clientId) {
        this.put(XConst.CLIENT_ID, clientId);
        return this;
    }

    public XUser setDataScope(String dataScope) {
        this.put(XConst.DATA_SCOPE, dataScope);
        return this;
    }

    public XUser setAuthorities(Collection<String> authorities) {
        this.put(XConst.AUTHORITIES, authorities);
        return this;
    }

    public boolean matches(String str, String regex) {
        return str != null && str.matches(regex);
    }

    public XUser pushMap(Object object) {
        if (object != null) {
            if (object instanceof Map) {
                Map<String, Object> map = (Map<String, Object>) object;
                if (map.size() > 0) {
                    for (Map.Entry<String, Object> entry : map.entrySet()) {
                        if (entry.getKey() != null) {
                            this.put(entry.getKey(), entry.getValue());
                        } else {
                            this.put(null, entry.getValue());
                        }
                    }
                }
            }
        }
        return this;
    }

    public Map<String, Object> getCacheMap() {
        Map<String, Object> result = new HashMap<>();
        if (this.size() > 0) {
            for (Map.Entry<String, Object> entry : this.entrySet()) {
                if (entry.getKey() != null) {
                    String key = entry.getKey().trim();
                    if (key.length() > 0) {
                        if (!key.equals(XConst.PASSWORD)) {
                            result.put(key, entry.getValue());
                        }
                    }
                }
            }
        }
        return result;
    }

    public boolean hasAnyAuthority(String... authorities) {
        if (this.isAdmin()) {
            return true;
        }
        if (authorities == null || authorities.length <= 0) {
            return false;
        }
        Collection<? extends GrantedAuthority> authorityList = this.getAuthorities();
        if (authorityList == null || authorityList.size() <= 0) {
            return false;
        }
        return authorityList.stream()
                .map(GrantedAuthority::getAuthority)
                .filter(StringUtils::hasText)
                .anyMatch(x -> PatternMatchUtils.simpleMatch(authorities, x));
    }

}

